﻿#include <iostream>
#include <easyx.h>  //只包含最新的API
#include <graphics.h>  //包含最新的api和一些已经过时的
#include <time.h>
#include <conio.h>
#pragma comment( lib, "MSIMG32.LIB")
#include <Windows.h>
#include <mmsystem.h>
#include <vector>
#pragma comment( lib, "winmm.lib")
using namespace std;

void transparentimage3(IMAGE* dstimg, int x, int y, IMAGE* srcimg) //新版png
{
  //展示透明png图片，需要依赖项
//#include <conio.h>
//#pragma comment( lib, "MSIMG32.LIB")
//项目=>属性=>链接器=>输入=>附加依赖项winmm.lib
  HDC dstDC = GetImageHDC(dstimg);
  HDC srcDC = GetImageHDC(srcimg);
  int w = srcimg->getwidth();
  int h = srcimg->getheight();
  BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
  AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
void transparentimage3(IMAGE* dstimg, int x, int y, IMAGE* srcimg, int srcX, int srcY, int imgWidth, int imgHeight)
{
  // 展示透明PNG图片，需要依赖项
  // #include <conio.h>
  // #pragma comment( lib, "MSIMG32.LIB")
  // 项目=>属性=>链接器=>输入=>附加依赖项winmm.lib

  HDC dstDC = GetImageHDC(dstimg);  // 获取目标图片的设备上下文
  HDC srcDC = GetImageHDC(srcimg);  // 获取源图片的设备上下文

  // 检查截取区域是否超出源图片范围
  int srcW = srcimg->getwidth();
  int srcH = srcimg->getheight();

  if (srcX < 0 || srcY < 0 || srcX + imgWidth > srcW || srcY + imgHeight > srcH)
  {
    // 如果超出范围，可以选择报错或者调整截取区域
    printf("Error: Source rectangle is out of bounds.\n");
    return;
  }

  // 设置混合函数参数
  BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };

  // 使用AlphaBlend函数将源图片的指定部分绘制到目标图片上
  AlphaBlend(dstDC, x, y, imgWidth, imgHeight, srcDC, srcX, srcY, imgWidth, imgHeight, bf);
}

void drawShape() {
  //绘制一个点
  putpixel(50,50,RED);
  //绘制一条线
  setlinecolor(GREEN);
  setlinestyle(PS_SOLID,3);
  line(0,0,getwidth(), getheight());

  //绘制一个矩形
  rectangle(100,0,100+50,0+50);
  setfillcolor(YELLOW);
  fillrectangle(100,50,100+50,50+50);
  //无边框填充矩形
  solidrectangle(100,100,100+50,100+50);
  //绘制圆角矩形
  roundrect(150,0,150+50,0+50,25,25);
  fillroundrect(150,50,150+50,50+50,25,25);
  solidroundrect(150,100,150+50,100+50,25,25);

  //绘制一个圆形
  circle(20,20,20);
  fillcircle(20,60,20);
  solidcircle(20,100,20);


  //椭圆
  ellipse(200,200,200+100,200+20); 
  fillellipse(300,200,300+100,200+20); 
  solidellipse(400,200,400+100,200+20); 

  //折线
  POINT points[] = { {0,0},{500,10},{20,30},{40,60},{78,99},{299,720},{30,60}};
  setlinecolor(RED);
  polyline(points,7);
}
void drawText() {
  
  printf("hello,easyx");

  //设置字体大小
  settextstyle(48,0,_T("宋体"));//width=0表示自适应
  //设置字体颜色
  settextcolor(GREEN);
  //设置字体背景填充模式
  setbkmode(TRANSPARENT);//transparent=不覆盖
  //绘制文字
  outtextxy(10,10,_T("你好，世界！"));
  //errorC2665：“outtextxy”：2个重载中没有一个可以转换所有参数类型
//EasyX与字符串相关的函数，都有字符集问题 UNICODE 多字节字符集
  /*三种解决方法：
*1，在字符串的前面使用L进行转换                         强制转换
*2,用带参宏（T()，_TEXT())把字符串包裹起来              自适应转换 推荐使用这种
*3，菜单栏->项目->属性->高级->字符集->把UNICODE改为多字节字符集   大力推荐这一种
  */

  settextstyle(30, 0, _T("宋体"));//width=0表示自适应
  //现在有一个int类型的分数，需要输出到图形界面上面
  int score = 59.5;
  char str[50] = "";
  sprintf_s(str,"Score:%d",score);
  outtextxy(getwidth()-200,0,str);
}
void centerText() {
  //写一个矩形，有填充、有边框
  int rx = 200;
  int ry = 200;
  int rw = 300;
  int rh = 200;

  setfillcolor(0x9968FF);//BGR
  fillrectangle(rx,ry,rx+rw,ry+rh);

  //绘制文字
  settextcolor(WHITE);
  char str[] = "center text";
  int hSpace = (rw - textwidth(str)) / 2;
  int vSpace = (rh - textheight(str)) / 2;
  outtextxy(rx+hSpace,ry+vSpace, str);
  
}
void messagePrint() {
  //定义消息结构体变量
  ExMessage msg = { 0 };
  while (true) {
    //获取消息
    if (peekmessage(&msg, EX_MOUSE)) {
      switch (msg.message)
      {
      case WM_LBUTTONDOWN://鼠标左键按下
        printf("鼠标左键按下 pos(%d,%d)\n", msg.x, msg.y);
        break;
      case WM_RBUTTONDOWN://鼠标右键按下
        printf("鼠标左键按下pos(%d,%d)\n", msg.x, msg.y);
        break;
      case WM_MBUTTONDOWN://鼠标中键按下
        printf("鼠标中键按下pos(%d,%d)\n", msg.x, msg.y);
        break;
      case WM_MOUSEWHEEL://鼠标滚轮滚动    正数是朝屏幕滚动，负数是朝玩家滚动
        printf("鼠标滚轮滚动dir(%d)\n", msg.wheel);
        break;
      case WM_LBUTTONDBLCLK: //左键双击
        printf("鼠标左键双击pos(%d,%d)\n", msg.x, msg.y);
        return;
        //case WM_MOUSEMOVE://鼠标移动
        //  printf("鼠标移动\n");
        //  break;
      }
    }
  }
}
bool inArea(int mx, int my, int x, int y, int w, int h) {
  //printf("%d\t%d\t%d\t%d\t%d\t%d\n",mx,my,x,y,x+w,y+h);
  if (mx >= x && mx <= x + w && my >= y && my <= y + h)
  {
    return 1;
  }
  else {
    return 0;
  }
}
void button(int x,int y, int w, int h, const char* text) {
  
  fillrectangle(x,y,x+w,y+h);//绘制矩形框
  int hSpace = (w - textwidth(text)) / 2;
  int vSpace = (h - textheight(text)) / 2;
  outtextxy(x + hSpace, y + vSpace, text);
}
void buttonMessage() {
  //定义小球的属性
  int x = 50;
  int y = 50;
  int r = 20;
  int speed = 5;//速度
  int vx = 0;
  int vy = 0;

  // 定义按钮状态
  bool startGame = false;
  bool endGame = false;

  //定义消息结构体变量
  ExMessage msg = { 0 };
  setbkmode(TRANSPARENT);
  int i = 0;
  while (true) {
    //获取消息
    if (peekmessage(&msg, EX_MOUSE|EX_KEY))
    {
      // 处理鼠标点击事件
      if (msg.message == WM_LBUTTONDOWN) {
        // 检测是否点击了按钮
        if (inArea(msg.x, msg.y, 20, 20, 150, 35)) {
          startGame = true;
          printf("Start Game!\n");
        }
        if (inArea(msg.x, msg.y, 300, 20, 150, 35)) {
          endGame = true;
          printf("End Game!\n");
        }
      }
    }
    //判断键盘输入
    //判断按键消息
    if (msg.message == WM_KEYDOWN)
    {
      //具体判断哪个键按下
      switch (msg.vkcode)
      {
      case VK_UP:
        vy = -1;
        printf("上键按下\t");
        break;
      case VK_DOWN:
        vy = 1;
        printf("下键按下\t");
        break;
      case VK_LEFT:
        vx = -1;
        printf("左键按下\t");
        break;
      case VK_RIGHT:
        vx = 1;
        printf("右键按下\t");
        break;
      case 'A'://对于字母按键一定要是大写
        printf("A键按下\t");
        break;
      case VK_SPACE:
        printf("空格按下\t");
        return;
      }
      printf("keydown\n");
    }
    else if (msg.message == WM_KEYUP) {
      //具体判断哪个键按下
      switch (msg.vkcode)
      {
      case VK_UP:
        vy = 0;
        printf("上键按下\t");
        break;
      case VK_DOWN:
        vy = 0;
        printf("下键按下\t");
        break;
      case VK_LEFT:
        vx = 0;
        printf("左键按下\t");
        break;
      case VK_RIGHT:
        vx = 0;
        printf("右键按下\t");
        break;
      }
    }


    //双缓冲绘图：所有的绘图代码必须放在begin和end之间
    BeginBatchDraw();
    cleardevice();

    // 绘制按钮
    settextcolor(BLACK);

    button(20, 20, 150, 35, "Start Game");
    button(300, 20, 150, 35, "End Game");

    // 如果点击了“Start Game”，开始移动小球
    if (startGame) {
      // 绘制小球
      setfillcolor(RGB(43, 145, 175));
      solidcircle(x, y, r);

      // 更新小球的位置
      x += speed * vx;
      y += speed * vy;

      // 检测边界碰撞
      if (x - r <= 0 || x + r >= getwidth()) vx = -vx;
      if (y - r <= 0 || y + r >= getheight()) vy = -vy;
    }

    EndBatchDraw();

    Sleep(10);
    //把消息类型设置为0
    msg.message = 0;
  }

}
void scoreFresh(int fps) {
//清屏========>cleardevice
//双缓冲======>batchdraw多次绘制先放到内存，endbatchdraw再一次性放到窗口上
//帧率控制====>
  char str[50] = "";//这个需要开大一点，不然越界容易崩溃
  int score = 0;
  setbkmode(TRANSPARENT);

  //fps控制
  const clock_t fpsTime = 1000 / fps;  //1秒60帧 = 16.6  每一帧应该花费的时间16.6ms
  int startTime = 0;
  int frameTime = 0;    //当前帧实际执行时间

  while (true) {

    startTime = clock();//毫秒数统计

    sprintf(str,"Score:%d",score++);

    //双缓冲防止闪频
    BeginBatchDraw();
    cleardevice();//用设置的背景颜色重新填充窗口以清屏，避免每次的字叠在一起
    outtextxy(20,20,str);
    EndBatchDraw();

    frameTime = clock() - startTime;  //总共需要消耗的毫秒数
    if (frameTime<fpsTime)
    {
      Sleep(fpsTime-frameTime);
    }
    //getchar();
  }

}
void loadImage() {
  //定义图片
  IMAGE img_mm;

  //加载图片
  //2. 相对路径
  loadimage(&img_mm, "assets/109951169714871793.jpg",300,300);
  //输出图片
  putimage(400, 400, &img_mm);
  //1. 绝对路径
  loadimage(&img_mm, "C:\\Users\\honev\\Pictures\\pqg.jpg",400,400);
  //输出图片
  putimage(0, 0, &img_mm);

  //掩码图透明贴图
  IMAGE img_plane[2];
  loadimage(img_plane + 0, "assets/planeNormal_1.jpg");
  loadimage(img_plane + 1, "assets/planeNormal_2.jpg");
  putimage(50, 100, img_plane + 0, NOTSRCERASE);//先绘制掩码图
  putimage(50, 100, img_plane + 1, SRCINVERT);//再绘制原图

  //png透明贴图
  IMAGE img_png;
  loadimage(&img_png, "assets/下载 (1).png");
  //putimage(100,100,&img_png);
  transparentimage3(NULL, 220, 100, &img_png);//透明png

} 
void animateImg() {
  //动画
  IMAGE img_enemy[4];
  //loadimage(img_enemy+0,"assets/enemy_down1.png");
  //loadimage(img_enemy+1,"assets/enemy_down2.png");
  //loadimage(img_enemy+2,"assets/enemy_down3.png");
  //loadimage(img_enemy+3,"assets/enemy_down4.png");
  char path[100] = {0};

  for (int i = 0; i < 4; i++)
  {
    sprintf(path,"assets/生成特定风格图片 (%d).png",i+1);
    loadimage(img_enemy + i, path);
  }
  //设置延时
  const int frameDelay = 1000;
  int frameStart = 0;
  int frameTime = 0;


  int index = 0;
  int frames = 4;
  int speed = 200;//每隔133ms切换一帧
  while (true) {

    frameStart = clock();

    BeginBatchDraw();
    cleardevice();
    transparentimage3(NULL, 0, 0, img_enemy+index);//透明png
    EndBatchDraw();

    //控制图片切换速度
    //防止index越界
    //index = (++index) % frames;
    index = (clock() / speed)%frames;
    printf("%d\n",index);

    //控制帧率
    frameTime = clock() - frameStart;
    if (frameDelay-frameTime>0)
    {
      Sleep(frameDelay-frameTime);
    }
  }

}
void pkqAnimate() {
  IMAGE img_sheet;
  loadimage(&img_sheet,"assets/pkq.png");
  //putimage(0,0,&img_sheet);

  int imgWidth = 921/3;     //每张图片的宽度
  int imgHeight = 1024/3;    //每张图片的高度
  int frames = 9;       //总共多少张
  int speed = 200;     //多少毫秒切换一张
  int index = 0;      //贴哪一张图
  int srcX[9] = { 0,1,2,0,1,2,0,1,2 };
  int srcY[9] = { 0,0,0,1,1,1,2,2,2 };


  //设置延时
  const int frameDelay = 1000;
  int frameStart = 0;
  int frameTime = 0;


  while (true) {
    frameStart = clock();

    BeginBatchDraw();
    cleardevice();
    //void putimage(int dstX, int dstY, int dstWidth, int dstHeight, const IMAGE * pSrcImg, int srcX, int srcY, DWORD dwRop = SRCCOPY);		// Put image to device
    //IMAGE* dstimg, int x, int y, IMAGE* srcimg, int srcX, int srcY, int imgWidth, int imgHeight
    transparentimage3(NULL, 250, 250, &img_sheet, srcX[index] * imgWidth, srcY[index] * imgHeight, imgWidth, imgHeight);

    EndBatchDraw();

    index = (clock() / speed) % frames;
    printf("\n%d",index);

  }
}

void playMusic_MP3(const char* music,int volume=-1,bool isRepeat=false) {
//#include <Windows.h>
//#include <mmsystem.h>
//#pragma comment( lib, "winmm.lib")
  
  //播放音乐 media control interface
  //mciSendString仅支持.wav和.MP3格式的音乐,.flac不支持
  //无法播放音乐的原因
  //1. 路径错误
  //2. 系统驱动不支持
  //3. 音乐文件格式错误
  // 方式一
  //mciSendString("open assets/summer.mp3",NULL,0,NULL);
  //mciSendString("play assets/summer.mp3",NULL,0,NULL);
  //方式二
  static int i = 0;
  char cmd[100] = { 0 };
  sprintf(cmd,"open %s alias bgm%d",music,i);
  mciSendString(cmd,NULL,0,NULL);
  //重复播放加repeat
  sprintf(cmd, "play bgm%d %s", i,isRepeat?"repeat":"");//每次调用，这个bgm别名不能相同，因此加个i来区分
  mciSendString(cmd,NULL,0,NULL);
  if (volume!=-1)
  {
    sprintf(cmd, "setaudio bgm%d volume to %d", i, volume);
    //如果失败则返回非0值，若成功返回0
    MCIERROR feedback = mciSendString(cmd, NULL, 0, NULL);//音量范围【0~1000】
    if (feedback != 0)
    {
      //获取错误信息
      char errText[100] = { 0 };
      mciGetErrorString(feedback, errText, sizeof(errText));
      puts(errText);//输出错误方式1
      printf("[volume]:%s", errText);//输出错误方式2，可以自定义格式
    }
  }

  i++;
}
void playMusic_WAV(const char* music,bool isRepeat=false) {
  //专门播放音效
  PlaySound(music,NULL,SND_FILENAME|SND_ASYNC);//无法播放mp3
  //循环播放
  while (isRepeat) {
    PlaySound(music, NULL, SND_FILENAME | SND_ASYNC);//无法播放mp3
    getchar();
  }
}

// 全局变量，用于记录鼠标轨迹
vector<pair<vector<POINT>, COLORREF>> curves;  // 存储每条曲线的点和颜色
bool isDrawing = false;  // 标志是否正在绘制曲线
int colorChoose = 0;     // 当前选择的颜色

// 设置颜色
COLORREF setColor() {
  switch (colorChoose) {
  case 0: return RED;
  case 1: return 0xC0CBFF;  // 粉色
  case 2: return BLACK;
  case 3: return WHITE;
  default: return RED;
  }
}

// 绘制所有曲线
void drawCurves() {
  for (const auto& curve : curves) {
    setlinecolor(curve.second);  // 设置曲线的颜色
    for (size_t i = 1; i < curve.first.size(); ++i) {
      line(curve.first[i - 1].x, curve.first[i - 1].y, curve.first[i].x, curve.first[i].y);  // 绘制线段
    }
  }
}

void paintBoard() {
  while (true) {
    // 绘制按钮
    BeginBatchDraw();
    cleardevice();
    setbkmode(TRANSPARENT);
    settextcolor(BLACK);
    setlinecolor(BLUE);
    setlinestyle(PS_SOLID, 2);

    //绘制按钮
    BeginBatchDraw();
    cleardevice();
    setbkmode(TRANSPARENT);
    settextcolor(BLACK);
    setlinecolor(BLUE);
    setlinestyle(PS_SOLID, 2);
    setfillcolor(RED);
    if (colorChoose == 0)
    {
      setlinecolor(GREEN);
    }
    button(0, 0, 48, 50, "red");
    setlinecolor(BLUE);
    if (colorChoose == 1)
    {
      setlinecolor(GREEN);
    }
    setfillcolor(0xC0CBFF);
    button(50, 0, 48, 50, "pink");
    setlinecolor(BLUE);
    if (colorChoose == 2)
    {
      setlinecolor(GREEN);
    }
    settextcolor(WHITE);
    setfillcolor(BLACK);
    button(100, 0, 48, 50, "black");
    setlinecolor(BLUE);
    if (colorChoose == 3)
    {
      setlinecolor(GREEN);
    }
    setfillcolor(WHITE);
    settextcolor(BLACK);
    button(150, 0, 48, 50, "white");

    // 获取消息
    ExMessage msg = { 0 };
    if (peekmessage(&msg, EX_MOUSE | EX_KEY)) {
      if (msg.message == WM_LBUTTONDOWN) {  // 鼠标左键按下
        isDrawing = true;
        vector<POINT> newCurve;
        newCurve.push_back({ msg.x, msg.y });  // 添加起点
        curves.push_back({ newCurve, setColor() });  // 添加新曲线并记录颜色
      }
      else if (msg.message == WM_MOUSEMOVE && isDrawing) {  // 鼠标移动且正在绘制
        if (!curves.empty()) {
          curves.back().first.push_back({ msg.x, msg.y });  // 添加新的轨迹点
        }
      }
      else if (msg.message == WM_LBUTTONUP) {  // 鼠标左键释放
        isDrawing = false;
      }
      if (msg.message == WM_KEYDOWN) {
        switch (msg.vkcode) {
        case 'A':
          colorChoose = (--colorChoose == -1 ? 3 : colorChoose) % 4;
          break;
        case 'D':
          colorChoose = (++colorChoose) % 4;
          break;
        case'C':
          curves.clear();  // 清空曲线数据
          break;
        default:
          break;
        }
      }
    }

    // 绘制所有曲线
    drawCurves();

    EndBatchDraw();
  }
}
int main()
{
  //创建一个窗口：宽度*高度
  initgraph(1000,512,EX_NOCLOSE | EX_SHOWCONSOLE | EX_NOMINIMIZE|EX_DBLCLKS);
  //initgraph(800,600);

  //设置窗口背景颜色
  setbkcolor(WHITE);                                          
  //用设置的背景颜色填充窗口
  cleardevice();
  //窗口的坐标系：左上是原点，x轴向右增大，y轴向下增大
  //画图形
  //drawShape();
  //drawText();
  //centerText();
  //messagePrint();
  //buttonMessage(); 
  //scoreFresh(10);
  //loadImage();
  //animateImg();
  //pkqAnimate();
  //playMusic_MP3("assets/summer.mp3",false);

  paintBoard();

  //防止程序退出
  getchar();
  return 0;
}

